package at.cookieforensics;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.DirectoryIteratorException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;

import com.gargoylesoftware.htmlunit.util.Cookie;
import com.sun.jna.platform.win32.WinBase.FILETIME;

/**
 * This class reads Cookies from the IE. 
 * 
 * @author markus.stoeckler
 * @version 1.0
 *
 */
public class InternetExplorer {
	/** String that contains the path to the cookie folder in Windows 8 */
	private String PathWIN8 = System.getProperty("user.home") + "\\AppData\\Local\\Microsoft\\Windows\\INetCookies\\";
	/** String that contains the path to the cookie folder in Windows 7 */
	private String PathWIN7 = System.getProperty("user.home") + "\\AppData\\Roaming\\Microsoft\\Windows\\Cookies\\";
	/** String that contains the path to the cookie folder in Windows XP */
	private String PathWINXP = System.getProperty("user.home") + "\\Cookies\\";
	/** String that contains the operating system, the version and the architecture */
	private String OS;
	/** ArrayList of com.gargoylesoftware.htmlunit.util.Cookie which contains all found cookies */
	public ArrayList<Cookie> AllCookies = new ArrayList<Cookie>(); 
	/** CookieLogger instance for logging */
	private CookieLogger cl = CookieLogger.getInstance();
	
	/**
	 * Constructor for the class InternetExplorer.
	 * Initializes class variables 
	 * @param OS contains the operating system, the version and the architecture
	 */
	public InternetExplorer(String OS){
        this.OS = OS;
        
        try {
        	findCookies();
        	cl.getLogger().info("Found " + AllCookies.size() +" Cookies");
        } catch (Exception e){
        	cl.getLogger().severe(e.getMessage());
        }
	}
	
	/**
	 * Reads all Cookie .txt-files from the IE into a string. 
	 * <br>Read method depends on Windows version.
	 * 
	 */
	public void findCookies(){
		ArrayList<String> fp = new ArrayList<String>();
		BufferedReader reader;
		String line, cookie = new String();

		if(OS.contains("8"))
			fp = getFiles(PathWIN8, null);
		else if(OS.contains("7"))
			fp = getFiles(PathWIN7, null);
		else
			fp = getFiles(PathWINXP, null);
		for(String file: fp){
			try {
				reader = new BufferedReader(new FileReader(file));
				while((line = reader.readLine()) != null){
					cookie += line + "\r\n";
				}
				readCookie(cookie);
				cookie = new String();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Separates a cookie string into single cookies
	 * 
	 * @param cookie Content of one cookie .txt-file
	 */
	private void readCookie(String cookie){
		String [] cookies = null;
		String [] cookieData = null;
		
        cookies = cookie.split("\\*\r\n");
        for(String temp : cookies){
                cookieData = temp.split("\r\n");
                if(cookieData[2].charAt(cookieData[2].length()-1) == '/'){
                	cookieData[2] = cookieData[2].substring(0, cookieData[2].length()-1);
                }
                AllCookies.add(new Cookie(cookieData[2], cookieData[0], cookieData[1]));
        }
	}
	
	/**
	 * Converts the FileTime of the saved cookie into java.util.Date
	 * 
	 * @param dwordOne Most significant DWORD of the FileTime Structure
	 * @param dwordTwo Least significant DWORD of the FileTime Structure
	 * @return FileTime as java.util.Date or the date of now if it fails
	 * @exception Exception the FileTime cannot get converted
	 */
	private Date timeConvert(String dwordOne, String dwordTwo){
		try{
			int leastSignificant = Integer.parseInt(dwordOne);
			int mostSignificant = Integer.parseInt(dwordTwo);
			Date date = FILETIME.filetimeToDate(leastSignificant, mostSignificant);
			
			return date;
		}
		catch(Exception e){
			cl.getLogger().warning("Cannot convert FileTime-structure to Date");
			return new Date();
		}
	}
	
	/**
	 * Checks if the isSecure flag is set
	 * 
	 * @param flag fourth value of a cookie
	 * @return true if the isSecure flag is set
	 */
	private boolean isSecure(String flag){
		return ((Long.parseLong(flag) & 0x2000) != 0);
	}
	
	/**
	 * Reads all .txt-files in the IE Cookie folder.
	 * <br>Also reads the low privilege folders (\Low)
	 * 
	 * @param dirPath Path to the IE Cookie folder
	 * @param actualList used for reading the low privileged folder recursive
	 * @return Paths of all found .txt-files
	 */
	private ArrayList<String> getFiles(String dirPath, ArrayList<String> actualList){
		Path dir = Paths.get(dirPath);
		ArrayList<String> temp;
		
		if (actualList == null){
			temp = new ArrayList<String>();
		}
		else{
			temp = actualList;
		}

		try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
		    for (Path file: stream) {
		    	if(file.getFileName().toString().contains(".txt")){
		    		temp.add(file.toAbsolutePath().toString());
		    	} else if(file.getFileName().toString().equals("Low")){
		    		getFiles(dirPath + "Low\\", temp);
		    	}
		    }    
		} catch (IOException | DirectoryIteratorException x) {
		    System.err.println(x);
		}
		
		return temp;
	}
}